﻿using System;
using System.Windows.Automation;

namespace QuickUIT.Controls
{
    /// <summary>
    /// Represents a window type control.  
    /// </summary>
    public class UIWindow : UIBaseControl
    {
        /// <summary>
        /// Gets a value which indicates whether the window can be maximized. 
        /// </summary>
        public new bool CanMaximize
        {
            get { return base.CanMaximize; }
        }

        /// <summary>
        /// Gets a value which indicates whether the window can be minimized. 
        /// </summary>
        public new bool CanMinimize
        {
            get { return base.CanMinimize; }
        }

        /// <summary>
        /// Gets a value which indicates whether the window is modal. 
        /// </summary>
        public new bool IsModal
        {
            get { return base.IsModal; }
        }

        /// <summary>
        /// Gets a value which indicates whether the window is the topmost element in z-order. 
        /// </summary>
        public new bool IsTopmost
        {
            get { return base.IsTopmost; }
        }

        /// <summary>
        /// Gets a the current state of a window control for the purposes of user interaction.
        /// If the control does not support the <see cref="WindowPattern"/>, a null reference is returned. 
        /// </summary>
        public new WindowInteractionState? WindowInteractionState
        {
            get { return base.WindowInteractionState; }
        }

        /// <summary>
        /// Gets the visual state of a window control (i.e. restored, minimized, maximized). 
        /// If the control does not support the <see cref="WindowPattern"/>, a null reference is returned.
        /// </summary>
        public new WindowVisualState? WindowVisualState
        {
            get { return base.WindowVisualState; }
        }

        /// <summary>
        /// Gets the dock position for the control. 
        /// If the control does not support the <see cref="DockPattern"/>, returns a null reference.  
        /// </summary>
        public new DockPosition? DockPosition
        {
            get { return base.DockPosition; }
        }

        /// <summary>
        /// Gets a value which indicates whether the control can be moved. 
        /// </summary>
        public new bool CanMove
        {
            get { return base.CanMove; }
        }

        /// <summary>
        /// Gets a value which indicates whether the control can be resized. 
        /// </summary>
        public new bool CanResize
        {
            get { return base.CanResize; }
        }

        /// <summary>
        /// Gets a value which indicates whether the control can be rotated. 
        /// </summary>
        public new bool CanRotate
        {
            get { return base.CanRotate; }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UIWindow"/> class. 
        /// </summary>
        public UIWindow(): base(ControlType.Window)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UIWindow"/> class.
        /// </summary>
        /// <param name="locator">The locator used to find the specific window.</param>
        public UIWindow(string locator) : base(null, ControlType.Window, locator)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UIWindow"/> class. 
        /// </summary>
        /// <param name="parent">The parent control.</param>
        public UIWindow(UIBaseControl parent) : base(parent, ControlType.Window)
        { 
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UIWindow"/> class. 
        /// </summary>
        /// <param name="parent">The parent control.</param>
        /// <param name="locator">The locator used to find the specific window.</param>
        public UIWindow(UIBaseControl parent, string locator) : base(parent, ControlType.Window, locator)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UIWindow"/> class
        /// </summary>
        /// <param name="element">The automation element for the window.</param>
        public UIWindow(AutomationElement element) : base(element)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UIWindow"/> class.
        /// </summary>
        /// <param name="parent">The parent of the control</param>
        /// <param name="control">The underlying <see cref="AutomationElement"/> of the control.</param>
        public UIWindow(UIBaseControl parent, AutomationElement control) : base(parent, control, ControlType.Window)
        {
        }

        /// <summary>
        /// Maximizes the current window. 
        /// </summary>
        /// <exception cref="InvalidOperationException">Thrown if the window cannot be maximized.</exception>
        public new void Maximize()
        {
            WaitUntilReady(AutomationConfiguration.Current.WindowWaitTime);
            AutomationElementPatterns.Maximize(Control); 
        }

        /// <summary>
        /// Minimizes the current window.
        /// </summary>
        /// <exception cref="InvalidOperationException">Thrown if the window cannot be minimized.</exception>
        public new void Minimize()
        {
            WaitUntilReady(AutomationConfiguration.Current.WindowWaitTime);
            AutomationElementPatterns.Minimize(Control); 
        }

        /// <summary>
        /// Restores the current window.
        /// </summary>
        /// <exception cref="InvalidOperationException">Thrown if the window cannot be restored.</exception>
        public new void Restore()
        {
            WaitUntilReady(AutomationConfiguration.Current.WindowWaitTime);
            AutomationElementPatterns.Restore(Control); 
        }

        /// <summary>
        /// Closes the current window. 
        /// </summary>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        public new void Close()
        {
            base.Close(); 
        }

        /// <summary>
        /// A safe method which will wait until the window is ready for more input. 
        /// </summary>
        /// <param name="timeout">The amount of time, in milliseconds, to wait for the window to become idle and ready.</param>
        public void WaitUntilReady(int timeout)
        {
            try
            {
                var windowPattern = AutomationElementPatterns.GetPattern<WindowPattern>(Control, WindowPattern.Pattern);
                if (windowPattern != null)
                {
                    AutomationElementPatterns.WaitForInputIdle(Control, timeout);
                }
            }
            catch (ElementNotAvailableException)
            {
                return; 
            }
        }

        /// <summary>
        /// Waits until the window enters the idle state or the timeout value is reached, whichever completes first. 
        /// </summary>
        /// <param name="timeout">The amount of time, in milliseconds, to wait for the window to become idle.</param>
        public void WaitForInputIdle(int timeout)
        {
            AutomationElementPatterns.WaitForInputIdle(Control, timeout);
        }

        /// <summary>
        /// Waits until the window is in the ready for user interaction state or until the timeout value is reached, whichever completes first. 
        /// </summary>
        /// <param name="timeout">The amount of time in milliseconds, to wait for the window to become ready for user interaction.</param>
        public void WaitUntilReadyForUserInteraction(int timeout)
        {
            var timer = new AutomationTimer(timeout);
            timer.Start();
            while (!timer.HasTimedOut())
            {
                var windowInteractionState = (WindowInteractionState) Control.GetCurrentPropertyValue(WindowPattern.WindowInteractionStateProperty);
                if (windowInteractionState == System.Windows.Automation.WindowInteractionState.ReadyForUserInteraction)
                {
                    return;
                }
            }
        }

        /// <summary>
        /// Sets the current dock position of the control.
        /// </summary>
        /// <param name="dockPosition">The new dock position.</param>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The current element does not exist anymore.</exception>
        public new void Dock(DockPosition dockPosition)
        {
            base.Dock(dockPosition);
        }

        /// <summary>
        /// Moves a control. 
        /// </summary>
        /// <param name="x">Absolute screen coordinates of the left side of the control.</param>
        /// <param name="y">Absolute screen coordinates of the top of the control.</param>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The current element does not exist anymore.</exception>
        public new void Move(double x, double y)
        {
            base.Move(x, y);
        }

        /// <summary>
        /// Resizes a control. 
        /// </summary>
        /// <param name="width">The new width of the window, in pixels.</param>
        /// <param name="height">The new height of the window, in pixels.</param>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The current element does not exist anymore.</exception>
        public new void Resize(double width, double height)
        {
            base.Resize(width, height);
        }

        /// <summary>
        /// Rotates a control. 
        /// </summary>
        /// <param name="degrees">The number of degrees to rotate the control. A positive number rotates clockwise; a negative number rotates counterclockwise.</param>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The current element does not exist anymore.</exception>
        public new void Rotate(double degrees)
        {
            base.Rotate(degrees);
        }
    }
}
